package com.huqing.icu.sdk.api;

import cn.hutool.core.io.FastByteArrayOutputStream;
import com.huqing.icu.enums.BusinessConstants;
import com.huqing.icu.exceptions.BusinessException;
import com.huqing.icu.sdk.config.MinioConfig;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description minio的api
 * @Author huqing
 * @Date 2025/9/17 16:22
 **/
@Component
public class MinioApiSdk {

    private static final Logger logger = LoggerFactory.getLogger(MinioApiSdk.class);

    @Autowired
    private MinioConfig minioConfig;
    @Autowired
    private MinioClient minioClient;

    /**
     * 文件上传
     * @param budget
     * @param minioObjectName
     * @param file
     */
    public void upload(String budget, String minioObjectName, MultipartFile file) {
        logger.info("begin upload file minioObjectName = {}, originalFilename = {}", minioObjectName, file.getOriginalFilename());

        String originalFilename = file.getOriginalFilename();
        if (StringUtils.isBlank(originalFilename)) {
            throw new RuntimeException();
        }

        try {
            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(budget).object(minioObjectName)
                    .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
            //上传文件，文件名称相同会覆盖
            minioClient.putObject(objectArgs);
            logger.info("uplaod file success, minioObjectName = {}, originalFilename = {}", minioObjectName, originalFilename);
        } catch (Exception e) {
            logger.info("uplaod file fail, minioObjectName = {}, originalFilename = {}, error: ", minioObjectName, originalFilename, e);
            throw  new BusinessException(BusinessConstants.FILE_UPLOAD_FAIL);
        }
    }

    /**
     * 下载文件
     * @param budget
     * @param objectName
     * @param fileName
     * @param response
     */
    public void download(String budget, String objectName, String fileName, HttpServletResponse response) {
        logger.info("begin download, filename = {}, objectName = {}", fileName, objectName);
        GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(budget).object(objectName).build();
        ServletOutputStream outputStream = null;

        try {
            GetObjectResponse getObjectResponse = minioClient.getObject(getObjectArgs);
            byte[] buf = new byte[1024];
            int len;

            FastByteArrayOutputStream os = new FastByteArrayOutputStream();
            while ((len = getObjectResponse.read(buf)) != -1) {
                os.write(buf, 0, len);
            }
            os.flush();
            byte[] bytes = os.toByteArray();
            response.setCharacterEncoding("utf-8");

            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
            outputStream = response.getOutputStream();
            outputStream.write(bytes);
            outputStream.flush();
        } catch (Exception e) {
            logger.error("download file objectName = {}, error: ", objectName, e);
            throw new BusinessException(BusinessConstants.FILE_DOWNLOAD_FAIL);
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                logger.error("outputStream close objectName = {}, error: ", objectName, e);
            }
        }
    }

    /**
     * 从minio获取文件
     * @param budget
     * @param objectName
     * @return
     */
    public MultipartFile getObject(String budget, String objectName) {
        InputStream inputStream;
        try {
            StatObjectArgs statObjectArgs = StatObjectArgs.builder().bucket(budget).object(objectName).build();
            StatObjectResponse statObjectResponse = minioClient.statObject(statObjectArgs);

            GetObjectArgs getObjectArgs = GetObjectArgs.builder().bucket(budget).object(objectName).build();
            inputStream = minioClient.getObject(getObjectArgs);

            MultipartFile multipartFile = new MockMultipartFile(objectName, objectName, statObjectResponse.contentType(), inputStream);

            inputStream.close();
            return multipartFile;
        } catch (Exception e) {
            logger.error("getObject file error = {}", e.toString());
            throw new BusinessException(BusinessConstants.FILE_DOWNLOAD_FAIL);
        }
    }

    /**
     * 删除文件
     * @param bucket
     * @param objectName
     * @return
     */
    public boolean deleteFile(String bucket, String objectName) {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectName).build());
        } catch (Exception e) {
            logger.error("delete file error: ", e);
        }
        return true;
    }

    /**
     * 批量删除文件
     * @param bucket
     * @param objectNameList
     * @return
     */
    public boolean deleteFiles(String bucket, List<String> objectNameList) {
        logger.info("begin batch delete file, objectNameList = {}", objectNameList);
        List<DeleteObject> deleteObjectList = objectNameList.stream().map(DeleteObject::new).collect(Collectors.toList());

        try {
            Integer failNum = 0;
            Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucket).objects(deleteObjectList).build());

            //必须遍历迭代器才能删除成功
            for (Result<DeleteError> result : results) {
                failNum = failNum + 1;
                DeleteError deleteError = result.get();
                logger.error("batch delete file error, objectName = {}, failNum = {}, error: ", deleteError.objectName(), failNum, deleteError.message());
            }

            if (failNum.equals(0)) {
                logger.info("batch delete file success, objectNameList = {}",objectNameList);
            }
        } catch (Exception e) {
            logger.error("batch delete file fail, error: ", e);

            //不要抛异常，不然导致mysql回滚了，minio没回滚
        }
        return true;
    }

    public String getObjectUrl(String budget, String objectName) {
        String url = null;
        try {
            url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(budget).object(objectName).build());
        } catch (Exception e) {
            logger.error("get url from minio error: ", e);
            throw new BusinessException(BusinessConstants.FILE_PREVIEW_FAIL);
        }
        return url;
    }
}
